import os
import pandas as pd
import json
import logging
from datetime import datetime
from typing import Dict, List, Any, Optional
from django.conf import settings
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from .models import ProcessingTask, UploadedFile, Template
from .utils import generate_unique_filename

logger = logging.getLogger(__name__)

class DataProcessingService:
    """数据处理服务类"""
    
    def __init__(self):
        self.supported_formats = ['xlsx', 'xls', 'csv', 'txt']
        self.output_formats = ['xlsx', 'csv', 'txt', 'json']
    
    def process_task(self, task: ProcessingTask) -> Dict[str, Any]:
        """处理任务"""
        try:
            logger.info(f"开始处理任务 {task.id}")
            
            # 更新任务状态
            task.status = 'processing'
            task.started_at = datetime.now()
            task.progress = 10
            task.save()
            
            # 步骤1: 读取源文件
            source_data = self._read_source_files(task)
            task.progress = 30
            task.save()
            
            # 步骤2: 应用模板配置
            processed_data = self._apply_template(task, source_data)
            task.progress = 60
            task.save()
            
            # 步骤3: 生成输出文件
            result_files = self._generate_output_files(task, processed_data)
            task.progress = 90
            task.save()
            
            # 步骤4: 完成任务
            task.status = 'completed'
            task.completed_at = datetime.now()
            task.progress = 100
            task.result_files = result_files
            task.save()
            
            logger.info(f"任务 {task.id} 处理完成")
            
            return {
                'success': True,
                'task_id': task.id,
                'result_files': result_files,
                'message': '任务处理完成'
            }
            
        except Exception as e:
            logger.error(f"任务 {task.id} 处理失败: {str(e)}")
            
            # 更新任务状态为失败
            task.status = 'failed'
            task.error_message = str(e)
            task.completed_at = datetime.now()
            task.save()
            
            return {
                'success': False,
                'task_id': task.id,
                'error': str(e),
                'message': '任务处理失败'
            }
    
    def _read_source_files(self, task: ProcessingTask) -> List[pd.DataFrame]:
        """读取源文件"""
        logger.info(f"读取任务 {task.id} 的源文件")
        
        source_files = task.source_files.all()
        if not source_files:
            raise ValueError("没有找到源文件")
        
        dataframes = []
        
        for file_obj in source_files:
            try:
                file_path = file_obj.file.path
                file_ext = os.path.splitext(file_obj.original_name)[1].lower()
                
                logger.info(f"读取文件: {file_obj.original_name}")
                
                if file_ext in ['.xlsx', '.xls']:
                    df = pd.read_excel(file_path)
                elif file_ext == '.csv':
                    # 尝试不同的编码
                    encodings = ['utf-8', 'gbk', 'gb2312', 'latin1']
                    df = None
                    for encoding in encodings:
                        try:
                            df = pd.read_csv(file_path, encoding=encoding)
                            break
                        except UnicodeDecodeError:
                            continue
                    if df is None:
                        raise ValueError(f"无法读取CSV文件 {file_obj.original_name}")
                elif file_ext == '.txt':
                    # 尝试读取为CSV格式
                    encodings = ['utf-8', 'gbk', 'gb2312', 'latin1']
                    df = None
                    for encoding in encodings:
                        try:
                            df = pd.read_csv(file_path, encoding=encoding, sep='\t')
                            break
                        except:
                            try:
                                df = pd.read_csv(file_path, encoding=encoding, sep=',')
                                break
                            except:
                                continue
                    if df is None:
                        raise ValueError(f"无法读取文本文件 {file_obj.original_name}")
                else:
                    raise ValueError(f"不支持的文件格式: {file_ext}")
                
                # 添加文件来源信息
                df.attrs['source_file'] = file_obj.original_name
                dataframes.append(df)
                
                logger.info(f"成功读取文件 {file_obj.original_name}，数据形状: {df.shape}")
                
            except Exception as e:
                logger.error(f"读取文件 {file_obj.original_name} 失败: {str(e)}")
                raise ValueError(f"读取文件 {file_obj.original_name} 失败: {str(e)}")
        
        return dataframes
    
    def _apply_template(self, task: ProcessingTask, source_data: List[pd.DataFrame]) -> List[pd.DataFrame]:
        """应用模板配置"""
        logger.info(f"为任务 {task.id} 应用模板配置")
        
        if not task.template:
            logger.info("没有指定模板，返回原始数据")
            return source_data
        
        try:
            template_config = json.loads(task.template.config)
            processed_data = []
            
            for i, df in enumerate(source_data):
                logger.info(f"处理第 {i+1} 个数据文件")
                
                processed_df = df.copy()
                
                # 应用列映射
                if 'column_mapping' in template_config:
                    column_mapping = template_config['column_mapping']
                    processed_df = processed_df.rename(columns=column_mapping)
                    logger.info(f"应用列映射: {column_mapping}")
                
                # 应用数据过滤
                if 'filters' in template_config:
                    filters = template_config['filters']
                    for filter_config in filters:
                        column = filter_config.get('column')
                        operator = filter_config.get('operator')
                        value = filter_config.get('value')
                        
                        if column in processed_df.columns:
                            if operator == 'equals':
                                processed_df = processed_df[processed_df[column] == value]
                            elif operator == 'not_equals':
                                processed_df = processed_df[processed_df[column] != value]
                            elif operator == 'contains':
                                processed_df = processed_df[processed_df[column].astype(str).str.contains(str(value), na=False)]
                            elif operator == 'greater_than':
                                processed_df = processed_df[processed_df[column] > value]
                            elif operator == 'less_than':
                                processed_df = processed_df[processed_df[column] < value]
                            
                            logger.info(f"应用过滤器: {column} {operator} {value}")
                
                # 应用数据转换
                if 'transformations' in template_config:
                    transformations = template_config['transformations']
                    for transform_config in transformations:
                        column = transform_config.get('column')
                        transform_type = transform_config.get('type')
                        
                        if column in processed_df.columns:
                            if transform_type == 'uppercase':
                                processed_df[column] = processed_df[column].astype(str).str.upper()
                            elif transform_type == 'lowercase':
                                processed_df[column] = processed_df[column].astype(str).str.lower()
                            elif transform_type == 'strip':
                                processed_df[column] = processed_df[column].astype(str).str.strip()
                            elif transform_type == 'date_format':
                                date_format = transform_config.get('format', '%Y-%m-%d')
                                processed_df[column] = pd.to_datetime(processed_df[column]).dt.strftime(date_format)
                            
                            logger.info(f"应用转换: {column} -> {transform_type}")
                
                # 应用列选择
                if 'selected_columns' in template_config:
                    selected_columns = template_config['selected_columns']
                    available_columns = [col for col in selected_columns if col in processed_df.columns]
                    if available_columns:
                        processed_df = processed_df[available_columns]
                        logger.info(f"选择列: {available_columns}")
                
                # 应用排序
                if 'sort_config' in template_config:
                    sort_config = template_config['sort_config']
                    sort_column = sort_config.get('column')
                    sort_order = sort_config.get('order', 'asc')
                    
                    if sort_column in processed_df.columns:
                        ascending = sort_order == 'asc'
                        processed_df = processed_df.sort_values(by=sort_column, ascending=ascending)
                        logger.info(f"应用排序: {sort_column} {sort_order}")
                
                processed_data.append(processed_df)
                logger.info(f"处理后数据形状: {processed_df.shape}")
            
            return processed_data
            
        except Exception as e:
            logger.error(f"应用模板配置失败: {str(e)}")
            raise ValueError(f"应用模板配置失败: {str(e)}")
    
    def _generate_output_files(self, task: ProcessingTask, processed_data: List[pd.DataFrame]) -> List[Dict[str, Any]]:
        """生成输出文件"""
        logger.info(f"为任务 {task.id} 生成输出文件")
        
        output_format = task.output_format or 'xlsx'
        result_files = []
        
        try:
            for i, df in enumerate(processed_data):
                source_name = df.attrs.get('source_file', f'data_{i+1}')
                base_name = os.path.splitext(source_name)[0]
                
                # 生成输出文件名
                timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
                output_filename = f"{base_name}_processed_{timestamp}.{output_format}"
                
                # 生成文件内容
                file_content = self._generate_file_content(df, output_format)
                
                # 保存文件
                file_path = os.path.join('results', str(task.id), output_filename)
                saved_path = default_storage.save(file_path, ContentFile(file_content))
                
                # 创建文件记录
                result_file = UploadedFile.objects.create(
                    original_name=output_filename,
                    file=saved_path,
                    file_size=len(file_content),
                    file_type=output_format,
                    source='result',
                    task=task
                )
                
                result_files.append({
                    'id': result_file.id,
                    'name': output_filename,
                    'size': len(file_content),
                    'type': output_format,
                    'path': saved_path
                })
                
                logger.info(f"生成输出文件: {output_filename}")
            
            return result_files
            
        except Exception as e:
            logger.error(f"生成输出文件失败: {str(e)}")
            raise ValueError(f"生成输出文件失败: {str(e)}")
    
    def _generate_file_content(self, df: pd.DataFrame, output_format: str) -> bytes:
        """生成文件内容"""
        if output_format == 'xlsx':
            import io
            buffer = io.BytesIO()
            with pd.ExcelWriter(buffer, engine='openpyxl') as writer:
                df.to_excel(writer, index=False, sheet_name='Data')
            return buffer.getvalue()
        
        elif output_format == 'csv':
            return df.to_csv(index=False, encoding='utf-8-sig').encode('utf-8-sig')
        
        elif output_format == 'txt':
            return df.to_csv(index=False, sep='\t', encoding='utf-8').encode('utf-8')
        
        elif output_format == 'json':
            return df.to_json(orient='records', ensure_ascii=False, indent=2).encode('utf-8')
        
        else:
            raise ValueError(f"不支持的输出格式: {output_format}")
    
    def validate_files(self, files: List[Any]) -> Dict[str, Any]:
        """验证上传的文件"""
        errors = []
        valid_files = []
        
        for file in files:
            # 检查文件大小
            if file.size > settings.FILE_UPLOAD_MAX_MEMORY_SIZE:
                errors.append(f"文件 {file.name} 超过大小限制")
                continue
            
            # 检查文件格式
            file_ext = os.path.splitext(file.name)[1].lower()
            if file_ext.lstrip('.') not in self.supported_formats:
                errors.append(f"文件 {file.name} 格式不支持")
                continue
            
            valid_files.append(file)
        
        return {
            'valid_files': valid_files,
            'errors': errors,
            'is_valid': len(errors) == 0
        }
    
    def preview_file(self, file_path: str, max_rows: int = 100) -> Dict[str, Any]:
        """预览文件内容"""
        try:
            file_ext = os.path.splitext(file_path)[1].lower()
            
            if file_ext in ['.xlsx', '.xls']:
                df = pd.read_excel(file_path, nrows=max_rows)
            elif file_ext == '.csv':
                # 尝试不同的编码
                encodings = ['utf-8', 'gbk', 'gb2312', 'latin1']
                df = None
                for encoding in encodings:
                    try:
                        df = pd.read_csv(file_path, encoding=encoding, nrows=max_rows)
                        break
                    except UnicodeDecodeError:
                        continue
                if df is None:
                    raise ValueError("无法读取CSV文件")
            elif file_ext == '.txt':
                # 尝试读取为CSV格式
                encodings = ['utf-8', 'gbk', 'gb2312', 'latin1']
                df = None
                for encoding in encodings:
                    try:
                        df = pd.read_csv(file_path, encoding=encoding, sep='\t', nrows=max_rows)
                        break
                    except:
                        try:
                            df = pd.read_csv(file_path, encoding=encoding, sep=',', nrows=max_rows)
                            break
                        except:
                            continue
                if df is None:
                    raise ValueError("无法读取文本文件")
            else:
                raise ValueError(f"不支持预览的文件格式: {file_ext}")
            
            # 转换为预览格式
            preview_data = {
                'type': 'table',
                'headers': df.columns.tolist(),
                'rows': df.fillna('').astype(str).values.tolist(),
                'total_rows': len(df),
                'total_columns': len(df.columns)
            }
            
            return preview_data
            
        except Exception as e:
            logger.error(f"预览文件失败: {str(e)}")
            return {
                'type': 'error',
                'message': f"预览文件失败: {str(e)}"
            }

class TaskQueueService:
    """任务队列服务类"""
    
    def __init__(self):
        self.processing_service = DataProcessingService()
    
    def submit_task(self, task: ProcessingTask) -> Dict[str, Any]:
        """提交任务到队列"""
        try:
            logger.info(f"提交任务 {task.id} 到处理队列")
            
            # 这里可以集成Celery或其他任务队列
            # 目前直接同步处理
            result = self.processing_service.process_task(task)
            
            return result
            
        except Exception as e:
            logger.error(f"提交任务失败: {str(e)}")
            return {
                'success': False,
                'error': str(e),
                'message': '提交任务失败'
            }
    
    def get_task_status(self, task_id: int) -> Dict[str, Any]:
        """获取任务状态"""
        try:
            task = ProcessingTask.objects.get(id=task_id)
            
            return {
                'task_id': task.id,
                'status': task.status,
                'progress': task.progress,
                'started_at': task.started_at,
                'completed_at': task.completed_at,
                'error_message': task.error_message
            }
            
        except ProcessingTask.DoesNotExist:
            return {
                'error': '任务不存在'
            }
        except Exception as e:
            logger.error(f"获取任务状态失败: {str(e)}")
            return {
                'error': str(e)
            }
    
    def cancel_task(self, task_id: int) -> Dict[str, Any]:
        """取消任务"""
        try:
            task = ProcessingTask.objects.get(id=task_id)
            
            if task.status in ['pending', 'processing']:
                task.status = 'cancelled'
                task.completed_at = datetime.now()
                task.save()
                
                logger.info(f"任务 {task_id} 已取消")
                
                return {
                    'success': True,
                    'message': '任务已取消'
                }
            else:
                return {
                    'success': False,
                    'message': '任务无法取消'
                }
                
        except ProcessingTask.DoesNotExist:
            return {
                'success': False,
                'error': '任务不存在'
            }
        except Exception as e:
            logger.error(f"取消任务失败: {str(e)}")
            return {
                'success': False,
                'error': str(e)
            }

# 全局服务实例
data_processing_service = DataProcessingService()
task_queue_service = TaskQueueService()